//==========================================================================
// Copyright (c) 2000-2009,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "CGrafixObject.h"
#include "_CGrafixObject.cpp"

ECode CGrafixObject::Initialize(
    /* [in] */ GrafixObjectStack * pStack,
    /* [in] */ CGrafixSurface * pSurface,
    /* [in] */ WString title,
    /* [in] */ GrafixObjectParams params)
{
    assert(pStack);
    assert(pSurface);

    ECode ec = NOERROR;

    // The grafixobject refers to the surface, but the surface doesn't record the
    // grafixobject's reference
    //
    pSurface->AddRef();
    m_surface = pSurface;

    m_stack = pStack;

    m_title = NULL;
    m_eventBuffer = NULL;
    m_ownerGrafixObject = NULL;
    m_needPaint = FALSE;
    m_contextId = 0xFFFFFFFF;
    m_appletId = 0xFFFFFFFF;
    m_status = GrafixObjectProperty_None;
    m_userDefinedId = NULL;
    m_userObject = NULL;
    m_userDefinedHandle = NULL;
    m_objId = GrafixObjectStack::GetWindowId();
    m_haveTimeEvent = FALSE;
    m_visible = FALSE;
    m_enableInput = TRUE;
    m_alive = TRUE;
    m_render = FALSE;
    m_bufferChanged = FALSE;
    m_visibleSwitch = GrafixObjectVisibleSwitch_None;
    m_animationFeasibility = AnimationFeasibility_None;
    m_animationQualification = AnimationQualification_None;
    m_leadingEffect = TransitionEffect_None;
    m_trailingEffect = TransitionEffect_None;

    m_sendClosedMessage = FALSE;

    m_exposed = FALSE;

    m_leadingOffsetX = 0;
    m_leadingOffsetY = 0;
    m_leadingOpacity = 0;
    m_leadingDuration = TransitionSpeed_Medium;

    m_trailingOffsetX = 0;
    m_trailingOffsetY = 0;
    m_trailingOpacity = 0;
    m_leadingDuration = TransitionSpeed_Medium;

    m_orientationChanged = FALSE;

    m_showing = FALSE;

#ifdef _DEBUG
    m_sign = GRAFIXOBJECT_SIGN;
#endif

    m_animationSymbol = FALSE;

    memset(&m_config, 0, sizeof(GrafixObjectConfig) - sizeof(RectangleLink));

    // opacity
    //
    m_config.opacity = 0xFF;

    if (params.attribute & GrafixAttribute_GrafixLayerChannel) {
        m_config.layerTransparentEnable = TRUE;
    }

    m_paintStatus = PaintStatus_None;

    m_config.activeArea.x = m_config.activeArea.y = 0;
    m_config.activeArea.width = m_config.activeArea.height = 0;

    for (Int32 i = 0; i < TIMER_COUNT; i++) {
        m_timeData[i].id = (UInt32)-1;
        m_timeEvent[i] = 0;
    }

    if (!title.IsNullOrEmpty()) {
        m_title = (wchar_t *)malloc(
                        (title.GetLength(_MAX_FNAME) + 1) * sizeof(wchar_t));
        if (!m_title) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("Create grafixobject's title that not enough memory\n"));

            return E_OUT_OF_MEMORY;
        }

        wcscpy(m_title, title);
    }

    m_config.option = params.attribute;
    m_config.bounds = params.objectArea;

    if (!(m_config.option & GrafixAttribute_Ghost)) {
        CGrafixObject* mainGrafixObject;

#ifdef _zener
        GFX_EXPRESSION(TRIPLEVEL, {
            Int32       id;

            ec = ::GetCurrentProcess()->GetId(&id);
            if (GFX_FAILED(ec)) {
                return ec;
            }

            assert(id == params.contextId);
        });
#endif

        g_lock.Lock();

        CGrafixEventBuffer  * eventBuffer;
        ec = m_stack->AcquireEventBuffer(params.contextId,
                                        &eventBuffer);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }

        m_contextId = params.contextId;
        m_eventBuffer = eventBuffer;

        m_stack->GetMainWindow(params.appletId, &mainGrafixObject);
        m_appletId = params.appletId;

        // The default priority is normal,
        // if the owner's main window's priority is more than new window's
        // priority, the new window's owner is NULL although that
        // the new window doesn't have the GrafixAttribute_NoDefaultOwner
        // attribute
        //

        // connect to the event buffer
        //
        if (NULL == mainGrafixObject) {
            m_type = GrafixObjectType_Main;
        }
        else {
            m_type = GrafixObjectType_Common;
            if (!mainGrafixObject->m_alive) {
                GFX_EXPRESSION(ERRORLEVEL,
                    kprintf("The main grafixobject %S has been closed\n", mainGrafixObject->m_title));
                ec = E_INVALID_OPERATION;

                goto Exit;
            }
        }

        assert(m_contextId == m_eventBuffer->m_contextId);

        if (m_config.option & GrafixAttribute_NoDefaultOwner) {
            assert(NULL == m_ownerGrafixObject);
            m_config.priority = StackingRank_Normal;
        }
        else {
            m_ownerGrafixObject = mainGrafixObject;

            if (mainGrafixObject) {
                m_config.priority = 0;
            }
            else {
                m_config.priority = StackingRank_Normal;
                assert(GrafixObjectType_Main == m_type);
            }
        }

Exit:
        g_lock.Unlock();
    }
    else {
        assert(NULL == m_ownerGrafixObject);
        m_config.priority = 0xFFFFFFFF;
    }

    return ec;
}

CGrafixObject::~CGrafixObject()
{
    assert(GRAFIXOBJECT_SIGN == m_sign);

    g_lock.Lock();

    assert(!m_userObject);

    if (m_alive) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Please close grafixobject %S first!\n", m_title));

        Close();
    }

    // remove the grafixobject from the grafixobjectstack.
    //
    if (m_stack) {
        m_stack->RemoveWindow(this);
    }

    if (m_eventBuffer) {
        assert(m_eventBuffer->m_contextId == m_contextId);
        m_eventBuffer->Release();
        m_eventBuffer = NULL;
    }

    GFX_EXPRESSION(DEBUG_DESTRUCTOR,
        kprintf("~CGrafixObject() %S, CGrafixSurface = 0x%08x\n", m_title, m_surface));

    if (m_title) {
        free(m_title);
        m_title = NULL;
    }

    if (m_surface) {
        m_surface->m_grafixObject = NULL;
        m_surface->Release();
    }

    g_lock.Unlock();
}

ECode CGrafixObject::GetId(
    /* [out] */Int32 * pObjId)
{
    if (!pObjId) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Argument invalid\n"));

        return E_INVALID_ARGUMENT;
    }

    // The id relate the grafix object, so after grafixobject be closed,
    // you can get it yet
    //
    *pObjId = m_objId;

    return NOERROR;
}

ECode CGrafixObject::GetTitle(
    /* [out] */ WStringBuf * pTitle)
{
    if (pTitle == NULL) {
        return E_INVALID_ARGUMENT;
    }
    if (!pTitle->GetCapacity()) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Argument invalid\n"));

        return E_INVALID_ARGUMENT;
    }

    if (m_title) {
        pTitle->Copy(m_title);
    }
    else {
        pTitle->Copy(L"");
    }

    return NOERROR;
}

ECode CGrafixObject::Attach(
    /* [in] */ Int32 appletId)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        CGrafixObject* grafixObject = NULL;
        Int32 index;

        if (GrafixObjectType_Main == m_type) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The main grafixobject can't attach to other grafixobject\n"));
            assert(m_contextId == m_eventBuffer->m_contextId);
            ec = E_INVALID_OPERATION;

            goto Exit;
        }

        // look up the main grafixobject of the application which is special
        // appletId.
        //
        for (index = 0; index < m_stack->m_windows.count; index++) {
            grafixObject = (CGrafixObject *)m_stack->m_windows.elements[index];
            if (grafixObject->m_appletId == appletId
                && grafixObject->m_contextId == m_contextId
                && grafixObject->m_type == GrafixObjectType_Main) {
                break;
            }
        }

        if (index != m_stack->m_windows.count) {
            if (m_eventBuffer) {
                if (m_eventBuffer == grafixObject->m_eventBuffer) {
                    goto Exit;
                }
                else {
                    GFX_EXPRESSION(ERRORLEVEL,
                        kprintf("please detach first\n"));
                    ec = E_INVALID_OPERATION;

                    goto Exit;
                }
            }

            m_appletId = appletId;
            assert(grafixObject->m_eventBuffer);
            grafixObject->m_eventBuffer->AddRef();
            m_eventBuffer   = grafixObject->m_eventBuffer;
        }
        else {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The main grafixObject of the application %d doesn't find\n",
                appletId));

            ec = E_WINDOW_NOT_FOUND;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixObject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::Detach()
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!m_eventBuffer) {
            goto Exit;
        }

        assert(m_stack->m_pointerWindow != this);
        assert(m_stack->m_keyboardWindow != this);

        if (GrafixObjectType_Main == m_type) {
            GFX_EXPRESSION(ERRORLEVEL,
                    kprintf("The main grafixObject can't detach event buffer\n"));
            ec = E_INVALID_OPERATION;

            goto Exit;
        }

        CleanEventBuffer();

        m_eventBuffer->Release();
        m_eventBuffer   = NULL;
        m_appletId = 0xFFFFFFFF;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::AddEvent(
    /* [in] */ const struct GrafixObjectEvent & event)
{
    GrafixObjectEvent inEvent = event;
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!m_eventBuffer) {
            GFX_EXPRESSION(WARNING,
                kprintf("The grafixobject %S not have the event buffer\n", m_title));

            goto Exit;
        }

        assert(m_enableInput
                || !(inEvent.type & GrafixObjectEventType_KeyDown
                || inEvent.type & GrafixObjectEventType_KeyUp
                || inEvent.type & GrafixObjectEventType_KeyHeld
                || inEvent.type & GrafixObjectEventType_StylusPressed
                || inEvent.type & GrafixObjectEventType_StylusLifted
                || inEvent.type & GrafixObjectEventType_StylusMove
                || inEvent.type & GrafixObjectEventType_StylusHeld));

        inEvent.objId       = m_objId;
        inEvent.userDefinedId   = m_userDefinedId;
        inEvent.userDefinedHandle     = m_userDefinedHandle;

        assert(m_contextId == m_eventBuffer->m_contextId);
        ec = m_eventBuffer->AddEvent(inEvent, m_status);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::AddNotifyEvent(
    /* [in] */ const struct GrafixObjectEvent & event)
{
    GrafixObjectEvent inEvent = event;
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!m_eventBuffer) {
            GFX_EXPRESSION(WARNING,
                kprintf("The grafixobject %S not have the event buffer\n", m_title));

            goto Exit;
        }

        assert(m_enableInput
                || !(inEvent.type & GrafixObjectEventType_KeyDown
                || inEvent.type & GrafixObjectEventType_KeyUp
                || inEvent.type & GrafixObjectEventType_KeyHeld
                || inEvent.type & GrafixObjectEventType_StylusPressed
                || inEvent.type & GrafixObjectEventType_StylusLifted
                || inEvent.type & GrafixObjectEventType_StylusMove
                || inEvent.type & GrafixObjectEventType_StylusHeld));

        inEvent.objId       = m_objId;
        inEvent.userDefinedId   = m_userDefinedId;
        inEvent.userDefinedHandle     = m_userDefinedHandle;

        assert(m_contextId == m_eventBuffer->m_contextId);
        ec = m_eventBuffer->AddNotifyEvent(m_appletId, inEvent);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::RollbackEvent(
    /* [in] */ const struct GrafixObjectEvent & event)
{
    GrafixObjectEvent inEvent = event;
    ECode ec = NOERROR;

    if (inEvent.objId != m_objId) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Must rollback yours event\n"));

        return E_INVALID_ARGUMENT;
    }

    if (!(inEvent.type & GrafixObjectEventType_StylusPressed
            || inEvent.type & GrafixObjectEventType_StylusLifted
            || inEvent.type & GrafixObjectEventType_StylusMove
            || inEvent.type & GrafixObjectEventType_StylusHeld)) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The event cannot be rollback\n"));

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        if (!m_eventBuffer) {
            GFX_EXPRESSION(WARNING,
                kprintf("The grafixobject %S not have the event buffer\n", m_title));

            goto Exit;
        }

        ec = m_stack->PostButtonEvent(inEvent);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

//
// TODO: Delete the second parameter
//
ECode CGrafixObject::SetUserDefinedHandles(
    /* [in] */ Handle32 usreDefinedId,
    /* [in] */ Handle32 usreDefinedHandle)
{
    ECode   ec = NOERROR;

    g_lock.Lock();

    m_userDefinedId = usreDefinedId;
    m_userDefinedHandle = usreDefinedHandle;

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetUserDefinedHandles(
    /* [out] */ Handle32 * pUsreDefinedId,
    /* [out] */ Handle32 * pUsreDefinedhandle)
{
    ECode ec = NOERROR;

    if (!pUsreDefinedId && !pUsreDefinedhandle) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        if (pUsreDefinedId) {
            *pUsreDefinedId = m_userDefinedId;
        }

        if (pUsreDefinedhandle) {
            *pUsreDefinedhandle = m_userDefinedHandle;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetOwner(
    /* [in] */ IGrafixObject * pOwnerObj)
{
    ECode       ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!pOwnerObj) {
            if (m_ownerGrafixObject) {
                m_config.priority += m_ownerGrafixObject->GetPriority();
            }

            m_ownerGrafixObject = NULL;
        }
        else {
            CGrafixObject* owner = (CGrafixObject *)pOwnerObj;
            if (!owner->m_alive) {
                GFX_ERROR_MESSAGE("The owner has been closed\n");
                ec = E_WINDOW_CLOSED;

                goto Exit;
            }

            // be sure that the owned grafixobject is not the owner's owner
            //
            CGrafixObject* p = owner->m_ownerGrafixObject;
            while (p) {
                if (p == this) {
                    GFX_EXPRESSION(ERRORLEVEL,
                        kprintf("This grafixobject is the owner's owner\n"));
                    ec = E_WINDOW_RECYCLE_OWN;

                    goto Exit;
                }

                p = p->m_ownerGrafixObject;
            }

            // be sure the owner's priority <= owned's priority
            //
            Int32 newPriority = GetPriority() - owner->GetPriority();
            if (newPriority < 0) {
                GFX_EXPRESSION(ERRORLEVEL,
                    kprintf("the owner's priority > this grafixobject's priority\n"));
                ec = E_WINDOW_MORE_PRIORITY;

                goto Exit;
            }

            m_config.priority = newPriority;
            m_ownerGrafixObject = owner;

            ec = m_stack->Restack(this);
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetOwner(
    /* [out] */ IGrafixObject ** ppOwnerObj)
{
    if (!ppOwnerObj) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    *ppOwnerObj = NULL;

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (m_ownerGrafixObject) {
            assert(m_ownerGrafixObject->m_appletId == m_appletId);

            m_ownerGrafixObject->AddRef();
            *ppOwnerObj = m_ownerGrafixObject;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetGrafixSurface(
    /* [out] */ IGrafixSurface ** ppGrafixSurface)
{
    if (!ppGrafixSurface) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    *ppGrafixSurface = NULL;

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        m_surface->AddRef();
        *ppGrafixSurface = m_surface;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetOpacity(
    /* [in] */ Int32 opacity)
{
    if (opacity == m_config.opacity) {
        return NOERROR;
    }

    if (!(m_config.option & GrafixAttribute_AlphaChannel)) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf(
                "The grafixobject which must be have the alpha channel attribute \
                can do this operation\n"));

        return E_INVALID_OPERATION;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (0 == m_config.opacity && 0 != opacity
                && TransitionEffect_None != m_leadingEffect) {
            m_animationQualification = AnimationQualification_Show;
        }

        if (0 != m_config.opacity && 0 == opacity
                && TransitionEffect_None != m_trailingEffect) {
            m_animationQualification = AnimationQualification_Hide;
        }

        m_config.opacity = opacity;

        m_stack->GetFlip();

        Region  update = REGION_INIT_FROM_RECTANGLE(&m_config.bounds);
        ec = m_stack->Update(&update);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetOpacity(
    /* [out] */ Int32 * pOpacity)
{
    if (!pOpacity) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    *pOpacity = 0;

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        *pOpacity = m_config.opacity;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::EnableGrafixLayerTransparent()
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!(m_config.option & GrafixAttribute_GrafixLayerChannel)) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The grafixobject %s doesn't have"
                        "the transparence capability.\n", m_title));
            ec = E_WINDOW_NOT_SUPPORT;

            goto Exit;
        }

        Boolean update = !m_config.layerTransparentEnable;

        m_config.layerTransparentEnable = TRUE;

        if (update && Visible()) {
            ec = Update();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::DisableGrafixLayerTransparent()
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!(m_config.option & GrafixAttribute_GrafixLayerChannel)) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The grafixobject %s doesn't have"
                        "the transparence capability.\n", m_title));
            ec = E_WINDOW_NOT_SUPPORT;

            goto Exit;
        }

        Boolean update = m_config.layerTransparentEnable;

        m_config.layerTransparentEnable = FALSE;

        if (update && Visible()) {
            ec = Update();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::AddGrafixLayerTransparentRect(
    /* [in] */ Int32 x,
    /* [in] */ Int32 y,
    /* [in] */ Int32 width,
    /* [in] */ Int32 height)
{
    Rectangle transparentRectangle = {x, y, width, height};

    if (!RectangleValid(&transparentRectangle)) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!(m_config.option & GrafixAttribute_GrafixLayerChannel)) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The grafixobject %S cannot set layer transparent\n",
                m_title));
            ec = E_WINDOW_NOT_SUPPORT;

            goto Exit;
        }

        ec = m_config.transparentRect.PreciseAdd(&transparentRectangle);
        if (GFX_FAILED(ec)) {
            m_config.transparentRect.PreciseRemove(&transparentRectangle);
            goto Exit;
        }

        if (Visible() && m_config.layerTransparentEnable) {
            Update();
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::RemoveGrafixLayerTransparentRect(
    /* [in] */ Int32 x,
    /* [in] */ Int32 y,
    /* [in] */ Int32 width,
    /* [in] */ Int32 height)
{
    Rectangle transparentRectangle = {x, y, width, height};

    if (!RectangleValid(&transparentRectangle)) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!(m_config.option & GrafixAttribute_GrafixLayerChannel)) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The grafixobject %S cannot set layer transparent\n",
                m_title));
            ec = E_WINDOW_NOT_SUPPORT;

            goto Exit;
        }


        m_config.transparentRect.PreciseRemove(&transparentRectangle);

        if (Visible() && m_config.layerTransparentEnable) {
            ec = Update();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::RemoveAllGrafixLayerTransparentRects()
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (!(m_config.option & GrafixAttribute_GrafixLayerChannel)) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The grafixobject %S cannot set layer transparent\n",
                m_title));
            ec = E_WINDOW_NOT_SUPPORT;

            goto Exit;
        }


        m_config.transparentRect.RemoveAll();

        if (Visible() && m_config.layerTransparentEnable) {
            m_stack->GetFlip();
            Update();
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GrabKey(
    /* [in] */ Int32 keyValue,
    /* [in] */ InputMask modifier)
{
    GrabbedKey* grab;
    ECode ec = NOERROR;
    Int32 i;

    g_lock.Lock();

    modifier = (InputMask)(modifier & ~0x80000001);

    if (m_alive) {
        Int32 index;

        for (index = 0; index < m_stack->m_grabbedKeys.count; index++) {
            GrabbedKey* grab =
                        (GrabbedKey*)m_stack->m_grabbedKeys.elements[index];
            if (keyValue == grab->keyValue && modifier == grab->modifier) {
                GFX_EXPRESSION(ERRORLEVEL,
                    kprintf("This key has been grabbed\n"));
                ec = E_ALREADY_EXIST;

                goto Exit;
            }
        }

#ifdef _DEBUG
        for (index = 0; index < m_stack->m_interceptedKeys.count; index++) {
            InterceptedKey* interception =
                (InterceptedKey *)m_stack->m_interceptedKeys.elements[index];
            if (keyValue == interception->keyValue
                    && modifier == interception->modifier
                    && this == interception->intercepter) {
                GFX_EXPRESSION(WARNING,
                    kprintf("The key 0x%08x(modifier 0x%08x)"
                    "has been %S(0x%08x) intercepted\n",
                    keyValue, modifier, m_title, this));
            }
        }
#endif

        grab = (GrabbedKey *)malloc(sizeof(GrabbedKey));
        if (!grab) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("Not enough memory\n"));
            ec = E_OUT_OF_MEMORY;

            goto Exit;
        }

        grab->keyValue = keyValue;
        grab->modifier = modifier;
        grab->grabber = this;
        FusionVectorAdd(&m_stack->m_grabbedKeys, grab);

        for (i = 0; i < KEY_CACHE; i++) {
            if (m_stack->m_keys[i].keyValue == keyValue) {
                m_stack->m_keys[i].keyValue   = -1;
                m_stack->m_keys[i].owner    = NULL;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::UngrabKey(
    /* [in] */ Int32 keyValue,
    /* [in] */ InputMask modifier)
{
    ECode ec = NOERROR;
#ifdef _DEBUG
    Boolean removed = FALSE;
#endif

    g_lock.Lock();

    if (m_alive) {
        for (Int32 index = m_stack->m_grabbedKeys.count - 1;
                index >= 0; index--) {
            GrabbedKey * grab =
                (GrabbedKey*)m_stack->m_grabbedKeys.elements[index];
            if (this == grab->grabber
                    && keyValue == grab->keyValue
                    && modifier == grab->modifier) {
                FusionVectorRemove(&m_stack->m_grabbedKeys, index);

                free((Void *)grab);

#ifdef _DEBUG
                assert(!removed);
                removed = TRUE;
#else
                break;
#endif
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GrabPointer()
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (m_stack->m_pointerWindow) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The grab pointer grafixobject has been already exist\n"));

            ec = E_ALREADY_EXIST;
        }
        else {
            m_stack->m_pointerWindow = this;

#ifdef _DEBUG
            if (!Visible()) {
                kprintf("The grafixobject %S invisible, but now GrabPoint\n",
                    m_title);
            }
#endif
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::UngrabPointer()
{
    ECode   ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (m_stack->m_pointerWindow == this) {
            m_stack->m_pointerWindow = NULL;

            ec = m_stack->UpdateFocus();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetPriority(
    /* [in] */ Int32 priority)
{
    if (priority > StackingRank_Highest) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The priority out of the range\n"));

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if ((UInt32)priority != GetPriority()) {
            if (m_ownerGrafixObject) {
                Int32 newPriority = priority - m_ownerGrafixObject->GetPriority();
                if (newPriority < 0) {
                    ec = E_WINDOW_MORE_PRIORITY;

                    goto Exit;
                }

                m_config.priority = newPriority;
            }
            else {
                m_config.priority = priority;
            }

            ec = RaiseToTop();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetPriority(
    /* [out] */ Int32 * pPriority)
{
    if (!pPriority) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Argument invalid\n"));

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        *pPriority = GetPriority();
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::Move(
    /* [in] */ Int32 deltaX,
    /* [in] */ Int32 deltaY)
{
    ECode   ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        Rectangle origionRect = m_config.bounds;

        m_config.bounds.x += deltaX;
        m_config.bounds.y += deltaY;

        Rectangle currentRect = m_config.bounds;

        if (!RectangleEqual(&origionRect, &currentRect)) {
            if (!(m_config.option & GrafixAttribute_Ghost)) {
                GrafixObjectEvent event;

                event.type = GrafixObjectEventType_BoundsChanged;
                event.relativeX = m_config.bounds.x;
                event.relativeY = m_config.bounds.y;
                event.absoluteX = m_config.bounds.width;
                event.absoluteY = m_config.bounds.height;
#ifdef _DEBUG
                ec =
#endif
                AddEvent(event);
#ifdef _DEBUG
                if (GFX_FAILED(ec)) {
                    goto Exit;
                }
#endif
            }

            if (Visible()) {
                Region updateRegion;

                if (!m_stack->GetFlip()) {
                    goto Exit;
                }

                RectangleUnion(&currentRect, &origionRect);
                RegionFromRectangle(&updateRegion, &currentRect);
                m_stack->Update(&updateRegion);
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::MoveTo(
    /* [in] */ Int32 x,
    /* [in] */ Int32 y)
{
    return Move(x - m_config.bounds.x, y - m_config.bounds.y);
}

ECode CGrafixObject::Resize(
    /* [in] */ Int32 width,
    /* [in] */ Int32 height)
{
    if (width <= 0 || height <= 0) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        ec = m_surface->SetBounds(0, 0, width, height,
                    (GrafixBound)(GrafixBound_Width | GrafixBound_Height));
        if (GFX_FAILED(ec)) {
            goto Exit;
        }

        assert(m_config.bounds.width == width);
        assert(m_config.bounds.height == height);

        ec = m_stack->Update();
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::RaiseToTop()
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
//        FusionVector* grafixObjects = &m_stack->m_windows;
//        for (Int32 index = grafixObjects->count - 1; index >= 0; index--) {
//            CGrafixObject* object = (CGrafixObject *)grafixObjects->elements[index];
//            if (object->m_appletId == m_appletId
//                    && TransitionEffect_None != object->m_leadingEffect
//                    && object->Visible()) {
//                object->m_animationQualification = AnimationQualification_Show;
//            }
//        }

        if (TransitionEffect_None != m_leadingEffect) {
            m_animationQualification = AnimationQualification_Show;
        }

        ec = m_stack->Restack(this);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::LowerToBottom()
{
    // TODO: Add your code here
    return E_NOT_IMPLEMENTED;
}

ECode CGrafixObject::RequestFocus()
{
    // TODO: Add your code here
    return E_NOT_IMPLEMENTED;
}

ECode CGrafixObject::SetTimer(
    /* [in] */ Int32 timerId,
    /* [in] */ Int32 interval)
{
    if (-1 == timerId ||0 >= interval) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Argument invalid\n"));

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        Int32 i;

        for (i = 0; i < TIMER_COUNT; i++) {
            if (timerId == m_timeData[i].id) {
                GFX_EXPRESSION(WARNING,
                    kprintf("The timerId already exist\n", timerId));

                ec = E_ALREADY_EXIST;

                goto Exit;
            }
        }

        for (i = 0; i < TIMER_COUNT; i++) {
            if (-1 == m_timeData[i].id) {
                break;
            }
        }

        if (i == TIMER_COUNT) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("The timer amount is already %d\n", TIMER_COUNT));

            ec = E_WINDOW_TIMER_TOO_MANY;

            goto Exit;
        }
        else {
            m_timeData[i].time = DzTicksToMilliseconds(DzGetElapsedTicks());
            if (GFX_FAILED(ec)) {
                goto Exit;
            }

            m_timeData[i].id = timerId;
            m_timeData[i].waitTime = interval;
            m_timeData[i].time += interval;

            if (!FusionVectorContains(&m_stack->m_timeWindows, this)) {
                ec = FusionVectorAdd(&m_stack->m_timeWindows, this);
                if (GFX_FAILED(ec)) {
                    goto Exit;
                }
            }

            if (m_stack->m_timeEvent) {
                ec = m_stack->m_timeEvent->Notify(SIGNALED);
                if (GFX_FAILED(ec)) {
                    goto Exit;
                }
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::KillTimer(
    /* [in] */ Int32 timerId)
{
    ECode ec = NOERROR;
    Int32 i;

    g_lock.Lock();

    if (m_alive) {
        Int32 count   = 0;
        Boolean exist= FALSE;

        for (i = 0; i < TIMER_COUNT; i++) {
            if (m_timeData[i].id != -1) {
                count++;
            }

            if (m_timeData[i].id == timerId) {
                assert(!exist);
                exist = TRUE;
                count--;
                m_timeData[i].id = -1;
                m_timeEvent[i] = 0;
            }
        }

        if (exist) {
            Boolean haveTimeEvent = FALSE;
            for (i = 0; i < TIMER_COUNT; i++) {
                if (m_timeData[i].id != -1 && m_timeEvent[i] != 0) {
                    haveTimeEvent = TRUE;
                    break;
                }
            }

            if (!haveTimeEvent) {
                m_haveTimeEvent = FALSE;
            }

            if (0 == count) {
                assert(FusionVectorContains(&m_stack->m_timeWindows, this));
                FusionVectorRemove(&m_stack->m_timeWindows,
                    FusionVectorIndexOf(&m_stack->m_timeWindows, this));
            }
        }
        else {
            ec = E_DOES_NOT_EXIST;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::Close()
{
    Int32 index;
    Void* p;
    ECode ec = NOERROR;

    g_lock.Lock();

    // The sub grafixobject would be closed, when the main grafixobject be closed.
    //
    if (m_alive) {
        if (GrafixObjectType_Main == m_type) {
            fusion_vector_foreach_reverse(p, index, m_stack->m_windows) {
                CGrafixObject* grafixObject = (CGrafixObject *)p;
                if ((grafixObject->m_appletId == m_appletId
                        && grafixObject != this) || grafixObject->m_ownerGrafixObject == this) {
                    assert(grafixObject != this);
                    grafixObject->CloseWithoutUpdate();
                }
            }
        }
        else {
            fusion_vector_foreach_reverse(p, index, m_stack->m_windows) {
                CGrafixObject* grafixObject = (CGrafixObject *)p;
                if (grafixObject->m_ownerGrafixObject == this) {
                    assert(grafixObject != this);
                    grafixObject->CloseWithoutUpdate();
                }
            }
        }

        ec = m_stack->CleanWindowResource(this);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }

        // grafixobject has been closed, so if GetFlip or Update failed,
        // Not effect the close func.
        //
        m_stack->GetFlip();
        m_stack->Update();
    }
    else {
        GFX_EXPRESSION(DEBUGLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    //
    // now, the relative windows have be set the close status, but not send the
    // close message, at the GetEvent(), the message will be created.
    //

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetProperty(
    /* [in] */ GrafixObjectProperty property)
{
    ECode   ec = NOERROR;

    property = property & (~GrafixObjectProperty_Main);

    if (property != GrafixObjectProperty_Moveable
            && property != GrafixObjectProperty_None
            && property != GrafixObjectProperty_Resizeable
            && property != GrafixObjectProperty_CoalesceStylusMove) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        m_status = property;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetProperty(
    /* [out] */ GrafixObjectProperty * pProperty)
{
    if (!pProperty) {
        return E_INVALID_ARGUMENT;
    }

    if (GrafixObjectType_Main == m_type) {
        *pProperty = m_status | GrafixObjectProperty_Main;
    }
    else {
        assert(GrafixObjectType_Common == m_type);
        *pProperty = m_status;
    }

    return NOERROR;
}

ECode CGrafixObject::SetVisible(
    /* [in] */ Boolean visible)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (m_visible != visible) {
            m_visible = visible;

            if (m_visible) {
                if (TransitionEffect_None != m_leadingEffect) {
                    m_animationQualification = AnimationQualification_Show;
                }
            }
            else if (TransitionEffect_None != m_trailingEffect) {
                m_animationQualification = AnimationQualification_Hide;
            }

            if (!m_stack->GetFlip()) {
                goto Exit;
            }

            ec = Update();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }

            GFX_EXPRESSION(DUMPSTACK, {
                kprintf("Set grafixobject(0x%08x) %S visible %d\n",
                    this, m_title, Visible());
                m_stack->Dump();});

            ec = m_stack->UpdateFocus();
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::IsVisible(
    /* [out] */ Boolean * pVisible)
{
    if (!pVisible) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    *pVisible = FALSE;

    ECode   ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        *pVisible = Visible();
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetInputEnabled(
    /* [in] */ Boolean enabled)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        m_enableInput = enabled;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::IsInputEnabled(
    /* [out] */ Boolean * pEnabled)
{
    ECode ec = NOERROR;

    if (!pEnabled) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The argument is invalid\n"));

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        *pEnabled = m_enableInput;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetBounds(
    /* [out] */ Int32 * pX,
    /* [out] */ Int32 * pY,
    /* [out] */ Int32 * pWidth,
    /* [out] */ Int32 * pHeight)
{
    if (!pX && !pY && !pWidth && !pHeight) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        if (pX) {
            *pX = m_config.bounds.x;
        }

        if (pY) {
            *pY = m_config.bounds.y;
        }

        if (pWidth) {
            *pWidth = m_config.bounds.width;
        }

        if (pHeight) {
            *pHeight = m_config.bounds.height;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetBounds(
    /* [in] */ Int32 x,
    /* [in] */ Int32 y,
    /* [in] */ Int32 width,
    /* [in] */ Int32 height,
    /* [in] */ GrafixBound bound)
{
    if ((bound & GrafixBound_Width && width < 1)
        || (bound & GrafixBound_Height && height < 1)) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        ec = m_surface->SetBounds(x, y, width, height, bound);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }

        assert(RectangleValid(&m_config.bounds));

        if (!m_stack->GetFlip()) {
            goto Exit;
        }

        Update();
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetActiveArea(
    /* [in] */ const struct Rectangle & area)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        Rectangle action = area;

        if (RectangleValid(&action)) {
            m_config.activeArea = action;
        }
        else {
            ec = E_REGION_TOO_SMALL;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::InterceptKey(
    /* [in] */ Int32 keyValue,
    /* [in] */ InputMask modifier)
{
    InterceptedKey* intercept;
    ECode ec = NOERROR;
    Int32 i;

    g_lock.Lock();

    modifier = (InputMask)(modifier & ~0x80000001);

    if (m_alive) {
        Int32     index;

        for (index = 0; index < m_stack->m_interceptedKeys.count; index++) {
            InterceptedKey* interception =
                (InterceptedKey *)m_stack->m_interceptedKeys.elements[index];
            if (keyValue == interception->keyValue
                    && modifier == interception->modifier
                    && this == interception->intercepter) {
                GFX_EXPRESSION(ERRORLEVEL,
                    kprintf("The window has intercept this key\n"));
                ec = E_ALREADY_EXIST;

                goto Exit;
            }
        }

#ifdef _DEBUG
        for (index = 0; index < m_stack->m_grabbedKeys.count; index++) {
            GrabbedKey* grab =
                        (GrabbedKey*)m_stack->m_grabbedKeys.elements[index];
            if (keyValue == grab->keyValue
                    && modifier == grab->modifier
                    && this == grab->grabber) {
                GFX_EXPRESSION(WARNING,
                    kprintf("The key 0x%08x(modifier 0x%08x) "
                    "has been %S(0x%08x) grabbed\n",
                    keyValue, modifier, m_title, this));
            }
        }
#endif

        intercept = (InterceptedKey *)malloc(sizeof(InterceptedKey));
        if (!intercept) {
            GFX_EXPRESSION(ERRORLEVEL,
                kprintf("Not enough memory\n"));
            ec = E_OUT_OF_MEMORY;

            goto Exit;
        }

        intercept->keyValue = keyValue;
        intercept->modifier = modifier;
        intercept->intercepter = this;

        FusionVectorAdd(&m_stack->m_interceptedKeys, intercept);

        for (i = 0; i < KEY_CACHE; i++) {
            if (m_stack->m_keys[i].keyValue == keyValue) {
                m_stack->m_keys[i].keyValue = -1;
                m_stack->m_keys[i].owner = NULL;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::UninterceptKey(
    /* [in] */ Int32 keyValue,
    /* [in] */ InputMask modifier)
{
    ECode ec = NOERROR;
#ifdef _DEBUG
    Boolean removed = FALSE;
#endif

    g_lock.Lock();

    if (m_alive) {
        for (Int32 index = m_stack->m_interceptedKeys.count - 1;
            index >= 0; index--) {
            InterceptedKey* intercept =
                (InterceptedKey *)m_stack->m_interceptedKeys.elements[index];
            if (this == intercept->intercepter
                    && keyValue == intercept->keyValue
                    && modifier == intercept->modifier) {
                FusionVectorRemove(&m_stack->m_interceptedKeys, index);

                free((Void *)intercept);

#ifdef _DEBUG
                assert(!removed);
                removed = TRUE;
#else
                break;
#endif
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetLeadingTransition(
    /* [in] */ TransitionEffect effect,
    /* [in] */ Int32 offsetX,
    /* [in] */ Int32 offsetY,
    /* [in] */ Int32 opacity,
    /* [in] */ Millisecond32 duration)
{
    ECode ec = NOERROR;

    if ((effect & 0x0000FF00)
            && effect != (TransitionEffect)TransitionEffect_Random) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        m_leadingEffect = effect;
        m_leadingOffsetX = offsetX;
        m_leadingOffsetY = offsetY;
        m_leadingOpacity = opacity;
        m_leadingDuration = duration;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::SetTrailingTransition(
    /* [in] */ TransitionEffect effect,
    /* [in] */ Int32 offsetX,
    /* [in] */ Int32 offsetY,
    /* [in] */ Int32 opacity,
    /* [in] */ Millisecond32 duration)
{
    ECode ec = NOERROR;

    if ((effect & 0x000000FF)
            && effect != (TransitionEffect)TransitionEffect_Random) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        m_trailingEffect = effect;
        m_trailingOffsetX = offsetX;
        m_trailingOffsetY = offsetY;
        m_trailingOpacity = opacity;
        m_trailingDuration = duration;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetLeadingTransition(
    /* [out] */ TransitionEffect * pEffect,
    /* [out] */ Int32 * pOffsetX,
    /* [out] */ Int32 * pOffsetY,
    /* [out] */ Int32 * pOpacity,
    /* [out] */ Millisecond32 * pDuration)
{
    if (!pEffect || !pOffsetX || !pOffsetY || !pOpacity || !pDuration) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        *pEffect = m_leadingEffect;
        *pOffsetX = m_leadingOffsetX;
        *pOffsetY = m_leadingOffsetY;
        *pOpacity = m_leadingOpacity;
        *pDuration = m_leadingDuration;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::GetTrailingTransition(
    /* [out] */ TransitionEffect * pEffect,
    /* [out] */ Int32 * pOffsetX,
    /* [out] */ Int32 * pOffsetY,
    /* [out] */ Int32 * pOpacity,
    /* [out] */ Millisecond32 * pDuration)
{
    if (!pEffect || !pOffsetX || !pOffsetY || !pOpacity || !pDuration) {
        GFX_ERROR_MESSAGE("Invalid argument\n");

        return E_INVALID_ARGUMENT;
    }

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        *pEffect = m_trailingEffect;
        *pOffsetX = m_trailingOffsetX;
        *pOffsetY = m_trailingOffsetY;
        *pOpacity = m_trailingOpacity;
        *pDuration = m_trailingDuration;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//          internal method                                                 //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

ECode CGrafixObject::NotifyEventBuffer(
    /* [in] */ NotifyType type)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (!m_eventBuffer) {
#ifndef CURSOR_VISIBLE
        GFX_EXPRESSION(
            m_config.option & GrafixAttribute_Ghost ? DEBUGLEVEL : WARNING,
            kprintf("The grafixobject %S not have the event buffer\n", m_title));
#endif

        goto Exit;
    }

    if (!m_alive) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        goto Exit;
    }

    assert(m_contextId == m_eventBuffer->m_contextId);
    ec = m_eventBuffer->Notify(type);
    if (GFX_FAILED(ec)) {
        goto Exit;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

//
// just set the status, doesn't update
//
ECode CGrafixObject::CloseWithoutUpdate()
{
    Int32 index;
    Void* p;

    if (!m_alive) {
        return NOERROR;
    }

    if (GrafixObjectType_Main == m_type) {
        fusion_vector_foreach_reverse(p, index, m_stack->m_windows) {
            CGrafixObject* grafixObject = (CGrafixObject *)p;
            if ((grafixObject->m_appletId == m_appletId && grafixObject != this)
                    || grafixObject->m_ownerGrafixObject == this) {
                assert(grafixObject != this);
                grafixObject->CloseWithoutUpdate();
            }
        }
    }
    else {
        fusion_vector_foreach_reverse(p, index, m_stack->m_windows) {
            CGrafixObject* grafixObject = (CGrafixObject *)p;
            if (grafixObject->m_ownerGrafixObject == this) {
                assert(grafixObject != this);
                grafixObject->CloseWithoutUpdate();
            }
        }
    }

    return m_stack->CleanWindowResource(this);
}

ECode CGrafixObject::__Impl_SetObject(
    /* [in] */ IInterface * pObject)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (pObject) {
        pObject->AddRef();
    }

    if (m_userObject) {
        m_userObject->Release();
    }

    m_userObject = pObject;

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::__Impl_GetObject(
    /* [out] */ IInterface ** ppObject)
{
    ECode   ec = NOERROR;

    if (!ppObject) {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("Invalid argument\n"));

        return E_INVALID_ARGUMENT;
    }

    g_lock.Lock();

    if (m_alive) {
        if (m_userObject) {
            m_userObject->AddRef();
        }

        *ppObject = m_userObject;
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::Update(
    /* [in] */ Region* updateRegion)
{
    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        Region region;

        if (!updateRegion) {
            RegionFromRectangle(&region, &m_config.bounds);
        }
        else {
            region = *updateRegion;
        }

        Rectangle screen = {0, 0, m_stack->m_width, m_stack->m_height};

        if (!RegionRectangleIntersect(&region, &screen)) {
            goto Exit;
        }

        Int32 end;

        if (!Visible() || Transparent()) {
            end = 0;
        }
        else {
            end = FusionVectorIndexOf(&m_stack->m_windows, this);
        }

        ec = m_stack->Update(&region, end);
        if (GFX_FAILED(ec)) {
            goto Exit;
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}

ECode CGrafixObject::Draw(
    /* [in] */ CGrafixSurface * pDestination,
    /* [in] */ Region * pRegion)
{
    assert(m_alive);
    assert(m_stack);
    assert(Visible());

    if (m_needPaint) {
        if (PaintStatus_Completed == m_paintStatus) {
            m_paintStatus = PaintStatus_None;
        }

        return NOERROR;
    }

    if (PaintStatus_Completed != m_paintStatus) {
        return NOERROR;
    }

    ECode ec = m_stack->m_engine->m_renderRect.PreciseAdd(pRegion);
    if (GFX_FAILED(ec)) {
        m_stack->m_engine->m_renderRect.PreciseRemove(pRegion);
        return NOERROR;
    }

    Rectangle draw = RECTANGLE_INIT_FROM_REGION(pRegion);

    RectangleTranslate(&draw,
                -(m_config.bounds.x),
                -(m_config.bounds.y));

    ec = pDestination->Blit(m_surface, draw, pRegion->left, pRegion->top, 0);
    if (GFX_FAILED(ec)) {
        return ec;
    }

    return NOERROR;
}

Void CGrafixObject::CleanEventBuffer()
{
    assert(m_stack);

    g_lock.Lock();

    if (m_eventBuffer) {
        m_eventBuffer->CleanEvent(this);
    }

    NotifyEventBuffer(NotifyType_Close);

    g_lock.Unlock();
}

ECode CGrafixObject::SetTimeEvent(
    /* [in] */ Int32 currentTime)
{
    assert(m_alive);

    for (Int32 i = 0; i < TIMER_COUNT; i++) {
        if (m_timeData[i].id != -1) {
            if (TimerID_NoInput == m_timeData[i].id) {
                if (m_stack->m_haveInput) {
                    assert(m_timeData[i].waitTime >= 0);
                    m_timeData[i].time = currentTime + m_timeData[i].waitTime;
                }
                else if (currentTime >= m_timeData[i].time) {
                    m_haveTimeEvent = TRUE;
                    m_timeEvent[i]++;
                    assert(m_timeData[i].waitTime >= 0);
                    m_timeData[i].time = currentTime + m_timeData[i].waitTime;
#ifdef _DEBUG
                    ECode ec =
#endif
                    NotifyEventBuffer(NotifyType_Timer);
                    assert(SUCCEEDED(ec));

                    m_stack->m_haveInput = FALSE;
                }
            }
            else {
                if (currentTime >= m_timeData[i].time) {
                    m_haveTimeEvent = TRUE;
                    m_timeEvent[i]++;
                    assert(m_timeData[i].waitTime >= 0);
                    m_timeData[i].time = currentTime + m_timeData[i].waitTime;
#ifdef _DEBUG
                    ECode ec =
#endif
                    NotifyEventBuffer(NotifyType_Timer);
                    assert(SUCCEEDED(ec));
                }
            }
        }
    }

    return NOERROR;
}

ECode CGrafixObject::SetBounds(
    /* [in] */ Rectangle * pRectangle)
{
    assert(pRectangle && RectangleValid(pRectangle));

    ECode ec = NOERROR;

    g_lock.Lock();

    if (m_alive) {
        Boolean boundsChanged = FALSE;

        if (m_config.bounds.x != pRectangle->x) {
            m_config.bounds.x = pRectangle->x;
            boundsChanged = TRUE;
        }

        if (m_config.bounds.y != pRectangle->y) {
            m_config.bounds.y = pRectangle->y;
            boundsChanged = TRUE;
        }

        if (m_config.bounds.width != pRectangle->width) {
            m_config.bounds.width = pRectangle->width;
            boundsChanged = TRUE;
        }

        if (m_config.bounds.height != pRectangle->height) {
            m_config.bounds.height = pRectangle->height;
            boundsChanged = TRUE;
        }

        if (boundsChanged && !(m_config.option & GrafixAttribute_Ghost)) {
            GrafixObjectEvent event;

            event.type = GrafixObjectEventType_BoundsChanged;
            event.relativeX = m_config.bounds.x;
            event.relativeY = m_config.bounds.y;
            event.absoluteX = m_config.bounds.width;
            event.absoluteY = m_config.bounds.height;
            ec = AddEvent(event);
            if (GFX_FAILED(ec)) {
                goto Exit;
            }
        }
    }
    else {
        GFX_EXPRESSION(ERRORLEVEL,
            kprintf("The grafixobject %S has been closed\n", m_title));

        ec = E_WINDOW_CLOSED;
    }

Exit:
    g_lock.Unlock();

    return ec;
}
